//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <usyscall.h>
#include "syscallno.h"

_ELASTOS_NAMESPACE_USING

#ifdef _GNUC


#ifdef _x86
#define DO_SYSCALL_0(n)                 \
    do {                                \
        register uint32_t ret;          \
        ASM("int    $0x80;"             \
            :"=a"(ret)                  \
            :"a"(n));                   \
        return ret;                     \
    } while (0)
#elif defined(_arm)
#define DO_SYSCALL_0(n)                 \
    do {                                \
        register uint32_t ret;          \
        ASM("mov    r5, #0;"            \
            "swi    %1;"                \
            "mov    %0, r0;"            \
            :"=r"(ret)                  \
            :"i"(n)                     \
            :"r0", "r5");               \
        return ret;                     \
    } while (0)
#elif defined(_mips)
#define DO_SYSCALL_0(n)                 \
    do {                                \
        register uint32_t ret;          \
        ASM(                            \
            "li     $2, %1;"            \
            "syscall;"                  \
            "move   %0, $2;"            \
            :"=r&"(ret)                 \
            :"i"(n)                     \
            :"$2");                     \
        return ret;                     \
    } while (0)
#else
$(error Unknown architecture)
#endif

#ifdef _x86
#define DO_SYSCALL_1(n, p1)             \
    do {                                \
        register uint32_t ret;          \
        ASM("int    $0x80;"             \
            :"=a"(ret)                  \
            :"a"(n), "b"(p1));          \
        return ret;                     \
    } while (0)
#elif defined(_arm)
#define DO_SYSCALL_1(n, p1)             \
    do {                                \
        register uint32_t ret;          \
        ASM("mov    r0, %2;"            \
            "mov    r5, #0;"            \
            "swi    %1;"                \
            "mov    %0, r0;"            \
            :"=r"(ret)                  \
            :"i"(n), "r"(p1)            \
            :"r0", "r5");               \
        return ret;                     \
    } while (0)
#elif defined(_mips)
#define DO_SYSCALL_1(n, p1)             \
    do {                                \
        register uint32_t ret;          \
        ASM(                            \
            "move   $4, %2;"            \
            "li     $2, %1;"            \
            "syscall;"                  \
            "move   %0, $2;"            \
            :"=r&"(ret)                 \
            :"i"(n), "r"(p1)            \
            :"$2", "$4");               \
        return ret;                     \
    } while (0)
#else
$(error Unknown architecture)
#endif

#ifdef _x86
#define DO_SYSCALL_2(n, p1, p2)         \
    do {                                \
        register uint32_t ret;          \
        ASM("int    $0x80;"             \
            :"=a"(ret)                  \
            :"a"(n), "b"(p1), "c"(p2)); \
        return ret;                     \
    } while (0)
#elif defined(_arm)
#define DO_SYSCALL_2(n, p1, p2)         \
    do {                                \
        register uint32_t ret;          \
        ASM("mov    r0, %2;"            \
            "mov    r1, %3;"            \
            "mov    r5, #0;"            \
            "swi    %1;"                \
            "mov    %0, r0;"            \
            :"=r"(ret)                  \
            :"i"(n), "r"(p1), "r"(p2)   \
            :"r0", "r1", "r5");         \
        return ret;                     \
    } while (0)
#elif defined(_mips)
#define DO_SYSCALL_2(n, p1, p2)         \
    do {                                \
        register uint32_t ret;          \
        ASM(                            \
            "move   $4, %2;"            \
            "move   $5, %3;"            \
            "li     $2, %1;"            \
            "syscall;"                  \
            "move   %0, $2;"            \
            :"=r&"(ret)                 \
            :"i"(n), "r"(p1),"r"(p2)    \
            :"$2", "$4", "$5");         \
        return ret;                     \
    } while (0)
#else
$(error Unknown architecture)
#endif

#ifdef _x86
#define DO_SYSCALL_3(n, p1, p2, p3)     \
    do {                                \
        register uint32_t ret;          \
        ASM("int    $0x80;"             \
            :"=a"(ret)                  \
            :"a"(n), "b"(p1), "c"(p2), "d"(p3)); \
        return ret;                     \
    } while (0)
#elif defined(_arm)
#define DO_SYSCALL_3(n, p1, p2, p3)     \
    do {                                \
        register uint32_t ret;          \
        ASM("mov    r0, %2;"            \
            "mov    r1, %3;"            \
            "mov    r2, %4;"            \
            "mov    r5, #0;"            \
            "swi    %1;"                \
            "mov    %0, r0;"            \
            :"=r"(ret)                  \
            :"i"(n), "r"(p1), "r"(p2), "r"(p3) \
            :"r0", "r1", "r2", "r5");   \
        return ret;                     \
    } while (0)
#elif defined(_mips)
#define DO_SYSCALL_3(n, p1, p2, p3)     \
    do {                                \
        register uint32_t ret;          \
        ASM(                            \
            "move   $4, %2;"            \
            "move   $5, %3;"            \
            "move   $6, %4;"            \
            "li     $2, %1;"            \
            "syscall;"                  \
            "move   %0, $2;"            \
            :"=&r"(ret)                 \
            :"i"(n), "r"(p1),"r"(p2)    \
                ,"r"(p3)                \
            :"$2", "$4", "$5", "$6");   \
        return ret;                     \
    } while (0)
#else
$(error Unknown architecture)
#endif

#ifdef _x86
#define DO_SYSCALL_4(n, p1, p2, p3, p4) \
    do {                                \
        register uint32_t ret;          \
        ASM("int    $0x80;"             \
            :"=a"(ret)                  \
            :"a"(n), "b"(p1), "c"(p2), "d"(p3), "S"(p4)); \
        return ret;                     \
    } while (0)
#elif defined(_arm)
#define DO_SYSCALL_4(n, p1, p2, p3, p4) \
    do {                                \
        register uint32_t ret;          \
        ASM("mov    r0, %2;"            \
            "mov    r1, %3;"            \
            "mov    r2, %4;"            \
            "mov    r3, %5;"            \
            "mov    r5, #0;"            \
            "swi    %1;"                \
            "mov    %0, r0;"            \
            :"=r"(ret)                  \
            :"i"(n), "r"(p1), "r"(p2), "r"(p3), "r"(p4) \
            :"r0", "r1", "r2", "r3", "r5"); \
        return ret;                     \
    } while (0)
#elif defined(_mips)
#define DO_SYSCALL_4(n, p1, p2, p3, p4) \
    do {                                \
        register uint32_t ret;          \
        ASM(                            \
            "move   $4, %2;"            \
            "move   $5, %3;"            \
            "move   $6, %4;"            \
            "move   $7, %5;"            \
            "li     $2, %1;"            \
            "syscall;"                  \
            "move   %0, $2;"            \
            :"=&r"(ret)                 \
            :"i"(n), "r"(p1),"r"(p2)    \
                ,"r"(p3), "r"(p4)       \
            :"$2", "$4", "$5", "$6"     \
                ,"$7");                 \
        return ret;                     \
    } while (0)
#else
$(error Unknown architecture)
#endif

#ifdef _x86
#define DO_SYSCALL_5(n, p1, p2, p3, p4, p5) \
    do {                                \
        register uint32_t ret;          \
        ASM("int    $0x80;"             \
            :"=a"(ret)                  \
            :"a"(n), "b"(p1), "c"(p2), "d"(p3), "S"(p4), "D"(p5)); \
        return ret;                     \
    } while (0)
#elif defined(_arm)
#define DO_SYSCALL_5(n, p1, p2, p3, p4, p5) \
    do {                                \
        register uint32_t ret;          \
        ASM("mov    r0, %2;"            \
            "mov    r1, %3;"            \
            "mov    r2, %4;"            \
            "mov    r3, %5;"            \
            "mov    r4, %6;"            \
            "mov    r5, #0;"            \
            "swi    %1;"                \
            "mov    %0, r0;"            \
            :"=r"(ret)                  \
            :"i"(n), "r"(p1), "r"(p2), "r"(p3), "r"(p4), "r"(p5) \
            :"r0", "r1", "r2", "r3", "r4", "r5"); \
        return ret;                     \
    } while (0)
#elif defined(_mips)
#define DO_SYSCALL_5(n, p1, p2, p3, p4, p5) \
    do {                                \
        register uint32_t ret;          \
        ASM(                            \
            "move   $4, %2;"            \
            "move   $5, %3;"            \
            "move   $6, %4;"            \
            "move   $7, %5;"            \
            "move   $8, %6;"            \
            "li     $2, %1;"            \
            "syscall;"                  \
            "move   %0, $2;"            \
            :"=&r"(ret)                 \
            :"i"(n), "r"(p1),"r"(p2)    \
             ,"r"(p3), "r"(p4), "r"(p5) \
            :"$2", "$4", "$5", "$6"     \
             ,"$7", "$8");              \
         return ret;                    \
    } while (0)
#else
$(error Unknown architecture)
#endif
#elif defined(_EVC)

#ifdef _mips
#define DO_SYSCALL_0(n)                 \
    do {                                \
        register uint32_t ret;          \
                                        \
        ASM(                            \
            "move   v0, %0;", n);       \
        ASM("syscall;");                \
        ASM(                            \
            "sw     v0, 0(%0)", &ret);  \
                                        \
        return ret;                     \
    } while (0);

#define DO_SYSCALL_1(n, p1)             \
    do {                                \
        register uint32_t ret;          \
        ASM(                            \
            "move   s0, %0;", n);       \
        ASM(                            \
            "move   t0, %0;"            \
            "syscall;", p1);            \
        ASM(                            \
            "sw     v0, 0(%0)", &ret);  \
                                        \
        return ret;                     \
    } while (0);

#define DO_SYSCALL_2(n, p1, p2)         \
    do {                                \
        register uint32_t ret;          \
                                        \
        ASM(                            \
            "move   v0, %0;", n);       \
        ASM(                            \
            "move   t0, %0;"            \
            "move   t1, %1;"            \
            "syscall;",                 \
            p1, p2);                    \
        ASM(                            \
            "sw     v0, 0(%0)", &ret);  \
                                        \
        return ret;                     \
    } while (0);

#define DO_SYSCALL_3(n, p1, p2, p3)     \
    do {                                \
        register uint32_t ret;          \
                                        \
        ASM(                            \
            "move   v0, %0;", n);       \
        ASM(                            \
            "move   t0, %0;"            \
            "move   t1, %1;"            \
            "move   t2, %2;"            \
            "syscall;",                 \
            p1, p2, p3);                \
        ASM(                            \
            "sw     v0, 0(%0)", &ret);  \
                                        \
        return ret;                     \
    } while (0);

#define DO_SYSCALL_4(n, p1, p2, p3, p4) \
    do {                                \
        register uint32_t ret;          \
                                        \
        ASM(                            \
            "move   v0, %0;", n);       \
        ASM(                            \
            "move   t0, %0;"            \
            "move   t1, %1;"            \
            "move   t2, %2;"            \
            "move   t3, %3;"            \
            "syscall;",                 \
            p1, p2, p3, p4);            \
        ASM(                            \
            "sw     v0, 0(%0)", &ret);  \
                                        \
        return ret;                     \
    } while (0);

#define DO_SYSCALL_5(n, p1, p2, p3, p4, p5) \
    do {                                \
        register uint32_t ret;          \
                                        \
        ASM(                            \
            "move   v0, %0;", n);       \
        ASM(                            \
            "move   t4, %0;", p5);      \
        ASM(                            \
            "move   t0, %0;"            \
            "move   t1, %1;"            \
            "move   t2, %2;"            \
            "move   t3, %3;"            \
            "syscall;",                 \
            p1, p2, p3, p4);            \
        ASM(                            \
            "sw     v0, 0(%0)", &ret);  \
                                        \
        return ret;                     \
    } while (0);
#else
$(error Unknown architecture)
#endif

#else
#error Unknown compiler
#endif

#ifndef _mips
SYSCALLAPI ECode SysPrint(const wchar_t * pwszMsg)
{
    DO_SYSCALL_1(CALLNO_SYS_PRINT, pwszMsg);
}

SYSCALLAPI ECode SysGetMemtraceArgs(wchar_t *pwchArgId, Int32 *pIndex, \
                                    Address *pWatchAddr)
{
    DO_SYSCALL_3(CALLNO_SYS_GETMEMTRACEARGS, pwchArgId, pIndex, pWatchAddr);
}

SYSCALLAPI ECode SysBreak(uint_t uAddr)
{
    DO_SYSCALL_1(CALLNO_SYS_BREAK, uAddr);
}

SYSCALLAPI ECode SysRegister(IStub *pIStub, EMuid *pCLSID, EIID * pIID, \
                             oid_t *pOid, CIClassEntry ** ppClsInfo)
{
    DO_SYSCALL_5(CALLNO_SYS_REGISTER, pIStub, pCLSID, pIID, pOid, ppClsInfo);
}

SYSCALLAPI ECode SysUnregister(oid_t oid)
{
    DO_SYSCALL_1(CALLNO_SYS_UNREGISTER, oid);
}

SYSCALLAPI ECode SysRegisterCommon(const wchar_t * pwszName, \
                      IStub * pIStub, EMuid * pCLSID, EIID * pIID, \
                      oid_t * pRet, CIClassEntry ** ppClsInfo)
{
    typedef struct _RegInArg {
        EMuid * pCLSID;
        EIID   * pIID;
    } RegInArg;

    RegInArg  regInArg = {pCLSID, pIID};
    DO_SYSCALL_5(CALLNO_SYS_REGISTER_COMMON, pwszName, pIStub, &regInArg, pRet, \
                 ppClsInfo);
}

SYSCALLAPI ECode SysResolveCommon(const wchar_t * pwszName, oid_t * pRet, \
                      EMuid *pClsid, UInt32 *puIndex, CIClassEntry ** ppClsInfo, \
                      PContext *ppContext)
{
    typedef struct _ResolveOutArg {
        CIClassEntry ** ppClsInfo;
        PContext *ppContext;
    } ResolveOutArg;

    ResolveOutArg resolveOutArg = {ppClsInfo, ppContext};
    DO_SYSCALL_5(CALLNO_SYS_RESOLVE_COMMON, pwszName, pRet, pClsid, puIndex, \
                 &resolveOutArg);
}

SYSCALLAPI ECode SysUnregisterCommon(const wchar_t * pwszName)
{
    DO_SYSCALL_1(CALLNO_SYS_UNREGISTER_COMMON, pwszName);
}

SYSCALLAPI ECode SysInvoke(oid_t oid, bool_t async, void *pvInBuf,
                     size_t uInBufSize, void *pvOutBuf, size_t uOutBufSize)
{
    typedef struct _InvokeInArg {
        oid_t oid;
        bool_t async;
    } InvokeInArg;

    InvokeInArg invokeInArg = {oid, async};
    DO_SYSCALL_5(CALLNO_SYS_INVOKE, &invokeInArg, pvInBuf, uInBufSize, \
        pvOutBuf, uOutBufSize);
}

SYSCALLAPI ECode SysReply(ECode ec,
                     void *pvOutBuf, size_t uOutBufSize)
{
    DO_SYSCALL_3(CALLNO_SYS_REPLY, ec, pvOutBuf, uOutBufSize);
}

SYSCALLAPI ECode SysRegisterClassInfo(CIClassInfo * pClassInfo)
{
    DO_SYSCALL_1(CALLNO_SYS_REGISTER_CLASS_INFO, pClassInfo);
}

SYSCALLAPI ECode SysGetClassInfo(EMuid *pClsid, CIClassEntry **ppClassInfo)
{
    DO_SYSCALL_2(CALLNO_SYS_GET_CLASS_INFO, pClsid, ppClassInfo);
}

SYSCALLAPI ECode SysExitThread(
                    /* [in] */ ECode exitCode)
{
    DO_SYSCALL_1(CALLNO_SYS_EXIT_THREAD, exitCode);
}

SYSCALLAPI ECode SysRegisterService(const wchar_t * pwszName, oid_t oid)
{
    DO_SYSCALL_2(CALLNO_SYS_REGISTER_SERVICE, pwszName, oid);
}

SYSCALLAPI ECode SysWaitService(
        const wchar_t * pwszName, Int32 msTimeout, WaitResult *pResult)
{
    DO_SYSCALL_3(CALLNO_SYS_WAIT_SERVICE, pwszName, msTimeout, pResult);
}

SYSCALLAPI ECode SysAttachServer(oid_t oid, PContext pContext)
{
    DO_SYSCALL_2(CALLNO_SYS_ATTACH_SERVER, oid, pContext);
}

SYSCALLAPI ECode SysDetachServer(oid_t oid, PContext pContext)
{
    DO_SYSCALL_2(CALLNO_SYS_DETACH_SERVER, oid, pContext);
}

SYSCALLAPI ECode SysCreateEvent(PVoid *pEventHandle)
{
    DO_SYSCALL_1(CALLNO_SYS_CREATE_EVENT, pEventHandle);
}

SYSCALLAPI ECode SysDestroyEvent(PVoid eventHandle)
{
    DO_SYSCALL_1(CALLNO_SYS_DESTROY_EVENT, eventHandle);
}

SYSCALLAPI ECode SysNotifyEvent(PVoid eventHandle)
{
    DO_SYSCALL_1(CALLNO_SYS_NOTIFY_EVENT, eventHandle);
}

SYSCALLAPI ECode SysWaitEvent(PVoid eventHandle)
{
    DO_SYSCALL_1(CALLNO_SYS_WAIT_EVENT, eventHandle);
}

SYSCALLAPI ECode SysSetBreakPoint(
        UInt32 uNo, BreakPointType type, void *pvAddress, UInt32 uLength)
{
    DO_SYSCALL_4(CALLNO_SYS_SET_BREAKPOINT, uNo, type, pvAddress, uLength);
}

SYSCALLAPI ECode SysGetVirtualCode(struct KBDStatus *pVirtulCode)
{
    DO_SYSCALL_1(CALLNO_SYS_GETVIRTUALCODE, pVirtulCode);
}

SYSCALLAPI ECode SysReboot()
{
    DO_SYSCALL_0(CALLNO_SYS_SYSREBOOT);
}

SYSCALLAPI ECode SysSleep(int ms, WaitResult *pResult)
{
    DO_SYSCALL_2(CALLNO_SYS_SLEEP, ms, pResult);
}

SYSCALLAPI ECode SysQueryPerformanceCounter(Int64 *pPerformanceCount, Int64 *pFrequency)
{
    DO_SYSCALL_2(CALLNO_SYS_QueryPerformanceCounter, pPerformanceCount, pFrequency);
}

SYSCALLAPI ECode SysGetThreadStackTop(UInt32 *pStackTop)
{
    DO_SYSCALL_1(CALLNO_SYS_GetThreadStackTop, pStackTop);
}

SYSCALLAPI ECode SysSendToKernel(UInt32 *buf, UInt32 type)
{
    DO_SYSCALL_2(CALLNO_SYS_SendToKernel, buf, type);
}

#endif
